﻿using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Tsual.Util;
using Tsual.Util.Redis;
using Tsual.Wechat.Cache;
using Tsual.Wechat.Message;
using Tsual.Wechat.Message.Exceptions;
using Tsual.Wechat.Message.Impl;
using Tsual.Wechat.Message.Impl.Internal;
using Tsual.Wechat.Message.Impl.Response;
using Tsual.Wechat.Message.Interface.Request;
using Tsual.Wechat.Message.Interface.Response;
using System.Web;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Mvc;
using System.Xml.Linq;
using System.Net;
using System.Collections;
using Tsual.Wechat;
using Tsual.Wechat.Formatters;
using Microsoft.AspNetCore.Hosting;
using Tsual.Wechat.Enums;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Tsual.Wechat.Filters;
using System.Reflection;
using Tsual.Wechat.Controllers;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Options;
using System.ComponentModel.DataAnnotations;
using Tsual.Wechat.Pipes;
using Tsual.DataPipeline;

namespace Tsual.Wechat
{
    public class WechatContext : ITsualWechatOption
    {
        internal IServiceProvider serviceProvider { get; set; }
        private WechatContext() { }
        internal ILogger logger { get; private set; }

        internal static WechatContext _Instance = new WechatContext();
        public static WechatContext Instance => _Instance.Configured ? _Instance : throw new InvalidOperationException("You have to initialize this class first.");

        internal T GetService<T>() => serviceProvider.GetService<T>();

        //public WechatMessageTemplate MessageTemplate { get; } = new WechatMessageTemplate();
        //public WechatUsers Users { get; } = new WechatUsers();
        public WechatBizMsgCrypt BizMsgCrypt { get; internal set; }
        public WechatMessageMaster MessageMaster { get; } = new WechatMessageMaster();

        public bool Configured { get; private set; }
        public string AppId { get; private set; }
        public string AppSecret { get; private set; }
        public string AesEncryptKey { get; private set; }
        public string Token { get; private set; }
        public string ControllerRoute { get; private set; }

        public string ResponseTextTimeout { get; private set; }
        public string ResponseTextNotfound { get; private set; }
        public string ResponseTextError { get; private set; }
        public string CacheHead { get; private set; }

        internal void Configure(IServiceProvider serviceProvider, string appId, string appSecret, string token, string cacheHead, string aesEncryptKey = null, string controllerRoute = "wechat",
            string txtTimeout = null, string txtError = null, string txtNotfound = null)
        {
            if (Configured) return;

            this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
            CacheHead = cacheHead ?? throw new ArgumentNullException(nameof(CacheHead));
            AppId = appId ?? throw new ArgumentNullException(nameof(appId));
            AppSecret = appSecret ?? throw new ArgumentNullException(nameof(appSecret));
            AesEncryptKey = aesEncryptKey;
            Token = token ?? throw new ArgumentNullException(nameof(token));
            ControllerRoute = controllerRoute ?? throw new ArgumentNullException(nameof(controllerRoute));

            ResponseTextError = txtError ;
            ResponseTextNotfound = txtNotfound;
            ResponseTextTimeout = txtTimeout;

            logger = serviceProvider?.GetService<ILogger<WechatContext>>();

            if (!string.IsNullOrEmpty(AesEncryptKey))
            {
                logger?.LogDebug($"EncodingAesKey[{AesEncryptKey}]Found==>configuring wechat encryptor");
                BizMsgCrypt = new WechatBizMsgCrypt(Token, AesEncryptKey, AppId);
            }
            else
            {
                logger?.LogDebug("EncodingAesKey not found,wechat encrytor configuration skip");
            }

            MessageMaster.SearchAssemblyAndRegistHandlersAsync(logger).Wait();

            Configured = true;
        }

        public string GetSignature(string timestamp, string nonce) => string.Join("", SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(string.Join("", new[] { Token, timestamp, nonce }.OrderBy(z => z)))).Select(x => string.Format("{0:x2}", x)));


        public async Task<string> GetAccessTokenAsync(bool force = false)
        {
            var pipe = serviceProvider.GetService<PmouldWechatCore>();
            return force ? (await pipe.AccessTokenForce.ReadAsync(DpmmAccessToken.Instance)).Data.Value : (await pipe.AccessToken.ReadAsync(DpmmAccessToken.Instance)).Data.Value;
        }

        public string GetAccessToken() => serviceProvider.GetService<PmouldWechatCore>().AccessToken.ReadAsync(DpmmAccessToken.Instance).GetResultOrThrowException().Value;

        //private async Task PostMenuAsyncInner(string post, string accessToken , HttpClient httpClient, bool isRetry = false)
        //{
        //    try
        //    {
        //        var response = await httpClient.PostAsync(NetExtensions.UrlAppendParam(@"https://api.weixin.qq.com/cgi-bin/menu/create", new KeyValuePair<string, string>("access_token", accessToken)), new StringContent(post, Encoding.UTF8, @"application/json"));
        //        if (response.IsSuccessStatusCode)
        //        {
        //            var rtn = JsonConvert.DeserializeObject<BasicWechatServerResponseModel>(await response.Content.ReadAsStringAsync());
        //            rtn.ThrowException();
        //            logger?.LogTrace("刷新微信菜单成功!");
        //        }
        //        else
        //        {
        //            await PostMenuAsyncInner(post, accessToken, httpClient, true);
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        if (isRetry)
        //        {
        //            logger?.LogError(ex, "刷新微信菜单报错(已经重试)");
        //            throw ex;
        //        }
        //        else
        //        {
        //            logger?.LogError(ex, "刷新微信菜单报错,正在重试");
        //            await PostMenuAsyncInner(post, accessToken, httpClient, true);
        //        }
        //    }
        //}

        //public async Task PostMenuAsync(object postData) => await PostMenuAsyncInner(postData is string spd ? spd : JsonConvert.SerializeObject(postData), await Instance.GetAccessTokenAsync(), Instance.GetService<IHttpClientFactory>().CreateClient());

        public async Task<WsrmUserAccessToken> GetUserAccessTokenAsync(string userOpenId = null, string pageCode = null)
        {
            var mould = serviceProvider.GetService<PmouldWechatCore>();
            var rlt = await mould.UserAccessToken.ReadAsync(new DpmmUserAccessToken(userOpenId, pageCode));
            logger.LogDebug(JsonConvert.SerializeObject(rlt));
            if (rlt.ReadStatus == DataPipelineExcutionStatus.Success)
                return rlt.Data;
            else throw new WechatApiException("获取用户许可意外失败");

            //var cache = Instance.GetService<IDatabase>();
            //{
            //    if (!string.IsNullOrEmpty(userOpenId))
            //    {
            //        logger.LogTrace("微信uat已经指定，开始寻找缓存，oid：{0}", userOpenId);
            //        var uat_key = WechatCacheKeyEnum.USER_ACCESS_TOKEN.ToRedisKey();
            //        var cached_uat = cache.HashGetExp(uat_key, userOpenId);
            //        if (!string.IsNullOrEmpty(cached_uat))
            //        {
            //            logger.LogTrace("微信uat缓存命中，oid:{0},uat:{1}", userOpenId, cached_uat);
            //            return cached_uat;
            //        }
            //        else
            //        {
            //            logger.LogTrace("微信uat缓存未命中，开始寻找urt缓存,oid:{0}", userOpenId);
            //        }

            //        var urt_key = WechatCacheKeyEnum.USER_REFRESH_TOKEN.ToRedisKey();
            //        var cached_urt = cache.HashGetExp(urt_key, userOpenId);
            //        if (!string.IsNullOrEmpty(cached_urt))
            //        {
            //            var start_time = DateTime.Now;
            //            var response = await Instance.GetService<IHttpClientFactory>().CreateClient().GetAsync(@"https://api.weixin.qq.com/sns/oauth2/refresh_token", new Dictionary<string, string>() {
            //                {"appid",WechatContext.Instance.AppId },
            //                {"grant_type","refresh_token" },
            //                {"refresh_token",cached_urt },
            //            }.ToArray());
            //            var response_content = await response.Content.ReadAsStringAsync();
            //            var uat = JsonConvert.DeserializeObject<WsrmUserAccessToken>(response_content);
            //            logger?.LogTrace("微信UserRefreshToken返回:{0}", response_content);
            //            uat.ThrowException();


            //            var uat_exp = start_time.GetRemainDuration(uat.expires_in);
            //            cache.HashSet(uat_key, uat.openid, uat.access_token, uat_exp);
            //            logger?.LogTrace("微信用户oid:{0}，accesstoken刷新{1}，过期时间{2}", uat.openid, uat.access_token, uat_exp);

            //            httpRefreshedCallback?.Invoke(uat);
            //            return cache.HashGetExp(uat_key, uat.openid);
            //        }
            //        else
            //        {
            //            logger.LogTrace("微信urt缓存未命中，开始执行页面回调code查询请求,oid:{0}", userOpenId);
            //        }
            //    }
            //}

            //if (string.IsNullOrEmpty(pageCode))
            //    throw new ArgumentNullException("pageCode", "当缓存未命中时不允许回调页面code为空");

            //{
            //    var httpClient = Instance.GetService<IHttpClientFactory>().CreateClient();
            //    var start_time = DateTime.Now;
            //    var response = await httpClient.GetAsync(@"https://api.weixin.qq.com/sns/oauth2/access_token", new Dictionary<string, string>() {
            //        {"appid",WechatContext.Instance.AppId },
            //        {"secret",WechatContext.Instance.AppSecret },
            //        {"code",pageCode },
            //        {"grant_type","authorization_code" }
            //    }.ToArray());
            //    var response_content = await response.Content.ReadAsStringAsync();
            //    var uat = JsonConvert.DeserializeObject<WsrmUserAccessToken>(response_content);
            //    logger?.LogTrace("微信UserAccessToken返回:{0}", response_content);
            //    uat.ThrowException();

            //    var uat_exp = start_time.AddSeconds(uat.expires_in);
            //    var uat_key = WechatCacheKeyEnum.USER_ACCESS_TOKEN.ToRedisKey();
            //    logger?.LogTrace("微信用户oid:{0}，accesstoken刷新{1}，过期时间{2}", uat.openid, uat.access_token, uat_exp);
            //    cache.HashSet(uat_key, uat.openid, uat.access_token, start_time.GetRemainDuration(uat.expires_in));

            //    var urt_exp = start_time.AddDays(30);
            //    var urt_key = WechatCacheKeyEnum.USER_REFRESH_TOKEN.ToRedisKey();
            //    logger?.LogTrace("微信用户oid:{0}，refreshtoken刷新{1}，过期时间{2}", uat.openid, uat.refresh_token, urt_exp);
            //    cache.HashSet(urt_key, uat.openid, uat.refresh_token, start_time.GetRemainDuration(uat.expires_in));

            //    httpRefreshedCallback?.Invoke(uat);
            //    return cache.HashGetExp(uat_key, uat.openid);
            //}
        }


    }

    //public class WechatMessageTemplate
    //{
    //    internal WechatMessageTemplate() { }

    //    public async Task<HttpResponseMessage> PostCompanyTradeAsync(WssmCompanyTradePost tradePost, HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
    //    {
    //        return await httpClient.PostAsync(NetExtensions.UrlAppendParam(@"https://api.weixin.qq.com/cgi-bin/template/api_set_industry", new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync())), new StringContent(JsonConvert.SerializeObject(tradePost), Encoding.UTF8, @"application/json"));
    //    }

    //    public async Task<WsrmCompanyTradeQuery> QueryCompanyTradeAsync(HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
    //    {
    //        var response = await httpClient.GetAsync(@"https://api.weixin.qq.com/cgi-bin/template/get_industry", args: new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync()));

    //        return await BasicWechatServerResponseModel.PackageServerReturnFromHttpResponseAsync<WsrmCompanyTradeQuery>(response);
    //    }

    //    public async Task<WsrmTemplateId> QueryTemplateIdByShortidAsync(string shortid, HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
    //    {
    //        var response = await httpClient.PostAsync(NetExtensions.UrlAppendParam(@"https://api.weixin.qq.com/cgi-bin/template/api_add_template", new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync())), new StringContent(JsonConvert.SerializeObject(new Dictionary<string, string>() { { "template_id_short", shortid } }), Encoding.UTF8, @"application/json"));

    //        return await BasicWechatServerResponseModel.PackageServerReturnFromHttpResponseAsync<WsrmTemplateId>(response);
    //    }

    //    public async Task<WsrmTemplateList> QueryTemplateListAsync(HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
    //    {
    //        var response = await httpClient.GetAsync(@"https://api.weixin.qq.com/cgi-bin/template/get_all_private_template", args: new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync()));

    //        return await BasicWechatServerResponseModel.PackageServerReturnFromHttpResponseAsync<WsrmTemplateList>(response);
    //    }

    //    public async Task<HttpResponseMessage> DeleteTempleteByidAsync(string TemplateId, HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
    //    {
    //        return await httpClient.PostAsync(NetExtensions.UrlAppendParam(@"https://api.weixin.qq.com/cgi-bin/template/del_private_template", new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync())), new StringContent(JsonConvert.SerializeObject(new Dictionary<string, string>() { { "template_id", TemplateId } }), Encoding.UTF8, @"application/json"));
    //    }

    //    public async Task<WsrmMessageid> SendTemplatedMessageAsync(WssmTemplateSend send, HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
    //    {
    //        send.appid = WechatContext.Instance.AppId;

    //        var response = await httpClient.PostAsync(NetExtensions.UrlAppendParam(@"https://api.weixin.qq.com/cgi-bin/message/template/send", new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync())), new StringContent(JsonConvert.SerializeObject(send), Encoding.UTF8, @"application/json"));

    //        return await BasicWechatServerResponseModel.PackageServerReturnFromHttpResponseAsync<WsrmMessageid>(response);
    //    }
    //}

//    public class WechatUsers
//    {
//        internal WechatUsers() { }

//        internal async Task QueryAllUsersInnerAsync(Queue<WsrmUsers> queue, HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, Action<WsrmUsers> callback = null, ILogger logger = null)
//        {
//            const int max = 10000;

//            var last = queue.LastOrDefault();
//            HttpResponseMessage response;
//            if (last == null)
//            {
//                response = await httpClient.GetAsync(@"https://api.weixin.qq.com/cgi-bin/user/get", args: new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync()));
//            }
//            else if (last.count < max)
//            {
//                return;
//            }
//            else if (last.count == max)
//            {
//                response = await httpClient.GetAsync(@"https://api.weixin.qq.com/cgi-bin/user/get", new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync()), new KeyValuePair<string, string>("next_openid", last.next_openid));
//            }
//            else
//            {
//                throw new WechatApiException($"微信服务器返回数量{last.count}超出上限{max}");
//            }
//            var obj = await BasicWechatServerResponseModel.PackageServerReturnFromHttpResponseAsync<WsrmUsers>(response);
//#pragma warning disable CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
//            if (callback != null) Task.Run(() => callback(obj));
//#pragma warning restore CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
//            queue.Enqueue(obj);
//            await QueryAllUsersInnerAsync(queue, httpClient, cache, lockFactory, callback, logger);
//        }

//        //public async Task CreateUserTagAndRefreshCacheAsync(string name, HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
//        //{
//        //    var response = await httpClient.PostAsync(NetExtensions.UrlAppendParam(@"https://api.weixin.qq.com/cgi-bin/message/template/send", new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync())), new StringContent(JsonConvert.SerializeObject(new Dictionary<string, Dictionary<string, string>>() { { "tag", new Dictionary<string, string>() { { "name", name } } } }), Encoding.UTF8, @"application/json"));

//        //    await BasicWechatServerResponseModel.PackageServerReturnFromHttpResponseAsync<BasicWechatServerResponseModel>(response);

//        //    cache.AddUserTags((await QueryAllTagsAsync(httpClient, cache, lockFactory, logger)).tags);
//        //}

//        //public async Task<WsrmUserTags> QueryAllTagsAsync(HttpClient httpClient, IDatabase cache, RedLockFactory lockFactory, ILogger logger = null)
//        //{
//        //    var response = await httpClient.GetAsync(@"https://api.weixin.qq.com/cgi-bin/tags/get", new KeyValuePair<string, string>("access_token", await WechatContext.Instance.GetAccessTokenAsync()));

//        //    return await BasicWechatServerResponseModel.PackageServerReturnFromHttpResponseAsync<WsrmUserTags>(response);
//        //}
//    }
}